﻿using MiniFox.Log;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Reflection;
using System.Text;

namespace MiniFox.Components
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class Component : IDisposable
    {
        bool _initialized;
        /// <summary>
        /// 
        /// </summary>
        public event EventHandler Disposed;
        /// <summary>
        /// 
        /// </summary>
        public Component()
        {
            _initialized = false;
            InitializeComponent();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        public Component(string name)
        {
            Name = name;
            _initialized = false;
            InitializeComponent();
        }

        #region release memory
        /// <summary>
        /// 
        /// </summary>
        ~Component()
        {
            Dispose(false);
        }
        bool _disposed;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            if (_disposed)
            {
                return;
            }

            if (disposing)
            {
                var type = GetType();
                var properties = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                foreach (var property in properties)
                {
                    var attr = property.GetCustomAttribute(typeof(AutoDisposeAttribute));
                    if (attr == null)
                        continue;
                    if (typeof(IDisposable).IsAssignableFrom(property.PropertyType))
                    {
                        var obj = property.GetValue(this, null) as IDisposable;
                        if (obj != null)
                            obj.Dispose();
                    }
                }
                var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                foreach (var field in fields)
                {
                    var attr = field.GetCustomAttribute(typeof(AutoDisposeAttribute));
                    if (attr == null)
                        continue;
                    if (typeof(IDisposable).IsAssignableFrom(field.FieldType))
                    {
                        var obj = field.GetValue(this) as IDisposable;
                        if (obj != null)
                            obj.Dispose();
                    }
                }
            }

            this.ReleaseUnmanagedResources();
            _disposed = true;
            Disposed?.Invoke(this, EventArgs.Empty);
        }
        /// <summary>
        /// 
        /// </summary>
        protected virtual void ReleaseUnmanagedResources()
        {

        }
        /// <summary>
        /// 
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion

        #region component related
        /// <summary>
        /// 组件容器
        /// </summary>
        protected virtual ComponentContainer Container
        {
            get { return ComponentFactory.Container; }
        }
        /// <summary>
        /// 组件名称
        /// </summary>
        public string Name
        {
            get;
            protected internal set;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="args"></param>
        /// <returns></returns>
        protected T GetComponent<T>(params object[] args)
        {
            return Container.GetComponent<T>(args);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        protected T GetComponentByName<T>(string name, params object[] args)
        {
            return Container.GetComponentByName<T>(name, args);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="contractType"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        protected object GetComponent(Type contractType, params object[] args)
        {
            return Container.GetComponent(contractType, args);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="contractType"></param>
        /// <param name="name"></param>
        /// <param name="args"></param>
        /// <returns></returns>
        protected object GetComponentByName(Type contractType, string name, params object[] args)
        {
            return Container.GetComponentByName(contractType, name, args);
        }
        #endregion

        #region auto load
        private void InitializeComponent()
        {
            if (!this._initialized)
            {
                this.Container.InitInstance(this);
                _initialized = true;
            }
        }
        #endregion

        #region log
        ILogger _logger;
        /// <summary>
        /// 
        /// </summary>
        protected virtual ILogger Logger
        {
            get
            {
                lock (this)
                {
                    if (_logger == null)
                    {
                        var loggerFactory = ComponentFactory.GetComponent<LoggerFactory>();
                        _logger = loggerFactory.CreateLogger();
                    }
                }
                return _logger;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        protected void WriteInfoLog(string content)
        {
            Logger.WriteInfo(new DefaultLogContent
            {
                Message = content
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="content"></param>
        /// <param name="exception"></param>
        protected void WriteWarnLog(string content, Exception exception)
        {
            Logger.WriteWarn(new DefaultLogContent
            {
                Message = content,
                Exception = exception
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="content"></param>
        /// <param name="exception"></param>
        protected void WriteErrorLog(string content, Exception exception)
        {
            Logger.WriteError(new DefaultLogContent
            {
                Message = content,
                Exception = exception
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="exception"></param>
        protected void WriteFatalLog(Exception exception)
        {
            Logger.WriteInfo(new DefaultLogContent
            {
                Exception = exception
            });
        }
        #endregion
    }

}
